package com.atguigu.config;

import com.atguigu.aop.LogAspects;
//import com.atguigu.aop.LogAspectsx;
import com.atguigu.aop.MathCalculator;
//import org.springframework.context.annotation.AspectJAutoProxyRegistrar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * AOP：【动态代理】
 *      指在程序运行期间动态的将末段代码切入到指定方法指定位置进行的编程方式
 * 1、导入aop模块；Spring AOP;(spring-aspects)
 * 2、需求:定义一个业务逻辑类;在业务逻辑前或者后进行打印
 * 3、定义一个日志切面类(LogAspects)
 *      通知方法:
 *          前置通知：LogStart(@Before)：在目标方法div运行之前执行
 *          后置通知: LogEnd(@After): 在目标方法div结束之后执行--无论正常或者异常结束
 *          返回通知：LogReturn(@AfterReturning)：在目标方法div正常结束之后执行
 *          异常通知：LogThrow(@AfterThrowing)：在目标方法div出现异常之后执行
 *          环绕通知：(@Around)动态代理；手动推进目标方法推进。joinPoint.procced()
 * 4、给切面类的目标方法标注何时何地执行
 *       共同的切入点---@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
 *       切入的时机---@Before("pointCut()")
 * 5、将切面类和业务逻辑类都加入到容器中去
 * 6、告诉spring哪一个是切面类(给切面类加入注解@Aspect)
 * 7、开启基于注解切面编程(@EnableAspectJAutoProxy)
 *
 * 三步:
 * 1）、将业务逻辑和切面类都要加入容器中去
 * 2)、切入点(pointCount)和切入时机(After)
 * 3)、开启基于注解切面编程(@EnableAspectJAutoProxy)
 *
 * aop实现的原理
 * {@link EnableAspectJAutoProxy}
 *      容器中添加了 {@link AspectJAutoProxyRegistrar}
 *                  -->容器中添加了 AnnotationAwareAspectJAutoProxyCreator--name是org.springframework.aop.config.internalAutoProxyCreator
 *      org.springframework.aop.config.internalAutoProxyCreator
 *      AnnotationAwareAspectJAutoProxyCreator
 *          AspectJAwareAdvisorAutoProxyCreator
 *              AbstractAdvisorAutoProxyCreator
 *                  AbstractAdvisorAutoProxyCreator
 *                      AbstractAutoProxyCreator -->implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
 *                          监控 setBeanFactory方法
 *                          监控 postProcessBeforeInstantiation
 *                          监控 postProcessAfterInstantiation
 *                          ProxyProcessorSupport
 *
 *
 *  创建单例bean的通用处理过程:
 *      实例化bean到容器中
 *      populateBean(beanName, mbd, instanceWrapper);--应用前置处理器并填充属性
 *      initializeBean(beanName, exposedObject, mbd);
 *      {
 * 			invokeInitMethods(beanName, wrappedBean, mbd);
 * 			applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 *      }
 */
@Configuration
@EnableAspectJAutoProxy
public class MainConfigAop {

    @Bean
    public MathCalculator mathCalculator() {
        return new MathCalculator();
    }

    @Bean
    public LogAspects logAspects() {
        return new LogAspects();
    }

//    @Bean
//    public LogAspectsx logAspectX() {
//        return new LogAspectsx();
//    }
}
